<?php

namespace ticky;

class debug {

    static $includefile = array();
    static $info = array();
    static $sqls = array();
    static $stoptime;
    static $msg = array(
        E_WARNING => '运行时警告',
        E_NOTICE => '运行时提醒',
        E_STRICT => '编码标准化警告',
        E_USER_ERROR => '自定义错误',
        E_USER_WARNING => '自定义警告',
        E_USER_NOTICE => '自定义提醒',
        'Unkown' => '未知错误'
    );

    /**
     * 注册异常处理
     * @access public
     * @return void
     */
    public static function register() {
        error_reporting(E_ALL);
        set_error_handler([__CLASS__, 'appError']);
        set_exception_handler([__CLASS__, 'appException']);
        register_shutdown_function([__CLASS__, 'appShutdown']);
    }

    /**
     * 错误处理
     * @access public
     * @param  integer $errno      错误编号
     * @param  integer $errstr     详细错误信息
     * @param  string  $errfile    出错的文件
     * @param  integer $errline    出错行号
     * @return void
     * @throws ErrorException
     */
    static function appError($errno = 0, $errstr = '', $errfile = '', $errline = 0) {
        if (!isset(self::$msg[$errno])) {
            $errno = 'Unkown';
        }
        if (strpos($errfile, '.html.php') == false) {
            runlog('error', 'appError:' . self::$msg[$errno] . ' ' . str_pad($errstr, 30) . ' ' . $errfile . ' ' . $errline);
        }
        if (APP_DEBUG) {
            if ($errno == E_NOTICE || $errno == E_USER_NOTICE) {
                $color = "#151515";
            } else {
                $color = "red";
            }
            if (strpos($errfile, '.html.php') !== false) {
                //模板错误不记录
            } else {
                $mess = '<span style="color:' . $color . '">';
                $mess .= '<b>' . self::$msg[$errno] . '</b> [文件 ' . $errfile . ' 中,第 ' . $errline . ' 行] ：';
                $mess .= $errstr;
                $mess .= '</span>';
                self::addmsg($mess);
            }
        }
    }

    /**
     * 致命错误 fatalerror
     */
    static function appShutdown() {
        if ($e = error_get_last()) {
            $errno = $e['type'];
            if (!isset(self::$msg[$errno])) {
                $errno = 'Unkown';
            }
            switch ($errno) {
                case E_ERROR:
                case E_PARSE:
                case E_CORE_ERROR:
                case E_COMPILE_ERROR:
                case E_USER_ERROR:
                    ob_end_clean();
                    runlog('error', 'appShutdown : ' . self::$msg[$errno] . ' ' . $e['message'] . ' ' . $e['file'] . ' ' . $e['line']);
                    if (APP_DEBUG) {
                        if (request::isAjax()) {
                            response::ajax($e);
                        } else {
                            app::fatalerror($e['message'], $e['file'] . ' on line ' . $e['line'], 1);
                        }
                    } else {
                        if (request::isAjax()) {
                            response::ajax($e);
                        } else {
                            app::halt('error message has been saved.');
                        }
                    }
                    break;
            }
        }
    }

    /**
     * 捕获异常
     * @param	object	$exception
     */
    static function appException($exception) {
        $title = $exception->getMessage();
        runlog('error', 'appException : ' . $title . '\t' . $exception->getFile() . '\t' . $exception->getLine());
        if (APP_DEBUG) {
            $mess = '<span style="color:red">';
            $mess .= '<b>系统异常</b> [文件 ' . $exception->getFile() . ' 中,第 ' . $exception->getLine() . ' 行] ：';
            $mess .= $title;
            $mess .= '</span>';
            self::addmsg($mess);
        }
        $msg = $exception->getFile() . ' on line ' . $exception->getLine();
        $errfile = $exception->getLine();
        if (!strpos($errfile, 'model.php')) {
            $sql = implode("<br>", self::$sqls);
            $msg .= '<br>SQL:<br>' . $sql;
        }
        $msg .= '<br>Trace: <br>"';
        $err = $exception->getTraceAsString();
        $pieces = explode("#", $err);
        foreach ($pieces as $str) {
            $msg .= $str . '<br>';
        }
        if (request::isAjax()) {
            response::ajax($exception);
        } else {
            app::fatalerror($title, $msg, 1);
        }
    }

    /**
     * 在脚本结束处调用获取脚本结束时间的微秒值
     */
    static function stop() {
        self::$stoptime = microtime(true);
    }

    /**
     * 返回同一脚本中两次获取时间的差值
     * 运行信息(x秒):
     */
    static function getUseTime($dec = 4) {
        return number_format((microtime(true) - TIMESTAMP), $dec);
    }

    /**
     * 添加调试消息
     * @param	string	$msg	调试消息字符串
     * @param	int	    $type	消息的类型
     */
    static function addmsg($msg, $type = 0) {
        switch ($type) {
            case 0:
                self::$info[] = $msg;
                break;
            case 1:
                self::$sqls[] = $msg . ';';
                break;
            case 2:
                self::$includefile[] = '<b>' . $msg . '.class.php</b> ';
                break;
        }
    }

    /**
     * 获取文件加载信息
     * @access public
     * @param  bool $detail 是否显示详细
     * @return integer|array
     */
    static function getFile($detail = false) {
        $files = get_included_files();
        if ($detail) {
            $info = [];
            foreach ($files as $file) {
                if (!strpos($file, 'smarty') !== false &&
                        !strpos($file, 'library') !== false &&
                        !strpos($file, 'vendor') !== false &&
                        !strpos($file, 'runtime') !== false &&
                        !strpos($file, 'tickyphp') !== false &&
                        !strpos($file, 'static') !== false
                ) {
                    $msg = "";
                    if (strpos($file, 'controller') !== false) {
                        $msg = "[控制器]";
                    } else if (strpos($file, 'lang') !== false) {
                        $msg = "[语言]";
                    } else if (strpos($file, 'config') !== false) {
                        $msg = "[配置]";
                    } else if (strpos($file, 'models') !== false) {
                        $msg = "[模型]";
                    } else if (strpos($file, 'extend') !== false) {
                        $msg = "[第三方]";
                    } else if (strpos($file, 'function') !== false) {
                        $msg = "[函数]";
                    }
                    $info[] = $msg . $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
                }
            }
            rsort($info);
            return $info;
        }
        return count($files);
    }

    /**
     * 获取当前访问的吞吐率情况
     * @access public
     * @return string
     */
    static function getThroughputRate() {
        return number_format(1 / self::getUseTime(), 2) . 'req/s';
    }

    /**
     * 统计从开始到统计时的内存使用情况
     * @access public
     * @param  integer $dec 小数位
     * @return string
     */
    static function getUseMem($dec = 2) {
        $size = memory_get_usage() - TICKY_START_MEM;
        $a = ['B', 'KB', 'MB', 'GB', 'TB'];
        $pos = 0;
        while ($size >= 1024) {
            $size /= 1024;
            $pos++;
        }
        return round($size, $dec) . " " . $a[$pos];
    }

    /**
     * 输出调试消息
     */
    static function message() {
        include(TICKY_PATH . DS . 'tpl' . DS . 'debug.tpl');
    }

}
